// --------------------------------------------------------------------------------------------------------------------
// <copyright file="TraceBase.cs" company="AzureContrib (Open source library http://azurecontrib.codeplex.com)">
//   Microsoft Public License (Ms-PL)
// </copyright>
// <summary>
//   Common base for <see cref="ITrace"/>.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

using System;
using System.Diagnostics.CodeAnalysis;

using AzureContrib.WindowsAzure.Properties;

using SD = System.Diagnostics;

namespace AzureContrib.WindowsAzure.Diagnostics
{
	/// <summary>
	/// Common base for <see cref="ITrace"/>.
	/// </summary>
	public abstract class TraceBase : ITraceSwitchable, ITraceControls
	{
		private readonly ITraceSwitchProvider traceSwitchProvider;
		private ITraceMessageFactory traceMessageFactory;

		/// <summary>
		/// Initializes a new instance of the <see cref="TraceBase"/> class.
		/// </summary>
		/// <param name="toTraceFor">The type we are tracing for.</param>
		/// <param name="traceSwitchProvider">A provider of switches.</param>
		[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "AzureContrib.WindowsAzure.Core.Assumes.NotNull handles null checking.")]
		[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "AzureContrib.WindowsAzure.Core.Assumes.NotNull handles null checking.")]
		protected TraceBase(Type toTraceFor, ITraceSwitchProvider traceSwitchProvider)
		{
			Assumes.NotNull(toTraceFor, "toTraceFor");
			Assumes.NotNull(traceSwitchProvider, "traceSwitchProvider");

			Switch = toTraceFor.FullName;
			this.traceSwitchProvider = traceSwitchProvider;

			System.Diagnostics.Trace.WriteLine(Strings.CreatedTraceForClass.F(toTraceFor.FullName), LogLevel.Verbose.ToString());
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="TraceBase"/> class.
		/// </summary>
		/// <param name="switch">The switch we are tracing to.</param>
		/// <param name="traceSwitchProvider">A provider of switches.</param>
		[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "AzureContrib.WindowsAzure.Core.Assumes.NotNull handles null checking.")]
		[SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "AzureContrib.WindowsAzure.Core.Assumes.NotNull handles null checking.")]
		protected TraceBase(string @switch, ITraceSwitchProvider traceSwitchProvider)
		{
			Assumes.NotNull(@switch, "@switch");

			if (string.IsNullOrEmpty(@switch.Trim()))
			{
				throw new ArgumentOutOfRangeException("switch", Strings.SwitchCannotBeWhiteSpaceOnly);
			}
		
			Assumes.NotNull(traceSwitchProvider, "traceSwitchProvider");

			Switch = @switch;
			this.traceSwitchProvider = traceSwitchProvider;

			System.Diagnostics.Trace.WriteLine(Strings.CreatedTraceForClass.F(@switch), LogLevel.Verbose.ToString());
		}

		/// <summary>
		/// Gets or sets a <see cref="ITraceMessageFactory"/> for generating the <see cref="TraceMessageBase"/> instances for each trace.
		/// </summary>
		public ITraceMessageFactory TraceMessageFactory
		{
			get
			{
				return traceMessageFactory ?? (traceMessageFactory = CreateTraceMessageFactory());
			}

			protected set
			{
				traceMessageFactory = value;
			}
		}

		/// <summary>
		/// Gets the current <see cref="ITraceSwitchProvider"/> in use.
		/// </summary>
		public ITraceSwitchProvider TraceSwitchProvider
		{
			get
			{
				return traceSwitchProvider;
			}
		}

		/// <summary>
		/// Gets a value indicating the switch name of the current trace target.
		/// </summary>
		public string Switch { get; private set; }

		/// <summary>
		/// Gets a value indicating whether	tracing is disabled for this <see cref="ITraceSwitchable.Switch"/>?
		/// </summary>
		/// <returns>True if tracing is disabled.</returns>
		public bool Disabled
		{
			get
			{
				return traceSwitchProvider.Disabled(this);
			}
		}

		/// <summary>
		/// Gets a value indicating whether	tracing at the Verbose level is enabled for this <see cref="ITraceSwitchable.Switch"/>?
		/// </summary>
		/// <returns>True if tracing is enabled.</returns>
		public bool VerboseEnabled
		{
			get
			{
				return traceSwitchProvider.VerboseEnabled(this);
			}
		}

		/// <summary>
		/// Gets a value indicating whether	tracing at the Info level is enabled for this <see cref="ITraceSwitchable.Switch"/>?
		/// </summary>
		/// <returns>True if tracing is enabled.</returns>
		public bool InformationEnabled
		{
			get
			{
				return traceSwitchProvider.InformationEnabled(this);
			}
		}

		/// <summary>
		/// Gets a value indicating whether tracing at the Warning level is enabled for this <see cref="ITraceSwitchable.Switch"/>?
		/// </summary>
		/// <returns>True if tracing is enabled.</returns>
		public bool WarningEnabled
		{
			get
			{
				return traceSwitchProvider.WarningEnabled(this);
			}
		}

		/// <summary>
		/// Gets a value indicating whether tracing at the Error level is enabled for this <see cref="ITraceSwitchable.Switch"/>?
		/// </summary>
		/// <returns>True if tracing is enabled.</returns>
		public bool ErrorEnabled
		{
			get
			{
				return traceSwitchProvider.ErrorEnabled(this);
			}
		}

		/// <summary>
		/// Gets a value indicating whether tracing at the Critical level is enabled for this <see cref="ITraceSwitchable.Switch"/>?
		/// </summary>
		/// <returns>True if tracing is enabled.</returns>
		public bool CriticalEnabled
		{
			get
			{
				return traceSwitchProvider.CriticalEnabled(this);
			}
		}

		/// <summary>
		/// Default <see cref="ITraceMessageFactory"/> is the <see cref="TraceMessageFactory"/>. Override to use a diffrent <see cref="TraceMessageBase"/> than the default <see cref="TraceMessage"/>.
		/// </summary>
		/// <returns>When not overriden the default is <see cref="TraceMessageFactory"/>.</returns>
		protected virtual ITraceMessageFactory CreateTraceMessageFactory()
		{
			return new TraceMessageFactory();
		}

		/// <summary>
		/// The <see cref="LogLevel"/>s as constant strings.
		/// </summary>
		internal static class LogLevelCategories
		{
			/// <summary>
			/// <see cref="LogLevel.Undefined"/> as a <see cref="string"/>.
			/// </summary>
			public const string Undefined = "Undefined";

			/// <summary>
			/// <see cref="LogLevel.Critical"/> as a <see cref="string"/>.
			/// </summary>
			public const string Critical = "Critical";

			/// <summary>
			/// <see cref="LogLevel.Error"/> as a <see cref="string"/>.
			/// </summary>
			public const string Error = "Error";

			/// <summary>
			/// <see cref="LogLevel.Warning"/> as a <see cref="string"/>.
			/// </summary>
			public const string Warning = "Warning";

			/// <summary>
			/// <see cref="LogLevel.Information"/> as a <see cref="string"/>.
			/// </summary>
			public const string Information = "Information";

			/// <summary>
			/// <see cref="LogLevel.Verbose"/> as a <see cref="string"/>.
			/// </summary>
			public const string Verbose = "Verbose";
		}
	}
}